#include "activeCurve.h"
#include "math.h"

// add one line to test svn in xcode
/* Generating  int vector */
int *int_vector(int n)
{
    int *v; 
    v = (int*) malloc(n*sizeof(int));
    return v;
}
/* Generate int matrix */
int **int_matrix(int m, int n)
{
    int **mat;
    int i;
    mat = (int**) malloc(m* sizeof(int*));
    for (i=0; i<m; i++)
        mat[i] = int_vector(n);
    return mat;
}

/*free matrix space*/
void free_matrix(void **a, int nrow, int ncol)
{
	int i;
	for(i = 0; i < nrow; i++)
		free(a[i]);
	free(a);
}

/* getting the index of matlab image, (x,y) location, (bx, by) sizes */
__inline  int px(int x, int y, int bx, int by) {
    return (x + (y-1)*bx - 1);
}

activeCurve::~activeCurve(){}

activeCurve::activeCurve(){
	initialized=false;
}

bool activeCurve::initial(imgData *p_image){
	nLength = p_image->n_length;
	nOrient = p_image->n_orient;
	nAngle = 1;

	h = p_image->h;
	S1map =p_image->S1map;

	sx = p_image->sx;
	sy = p_image->sy;
	
	Lrange = p_image->l_range;
	Orange = p_image->o_range;

	allsymbol = p_image->allsymbol;

	storeShift();
	arcShift();
	initialized =true;
	return true;
}


void activeCurve::release(){
	if(initialized==true){
		free_matrix((void**)startDx,nOrient*nAngle,nLength);
		free_matrix((void**)startDy,nOrient*nAngle,nLength);	
free_matrix((void**)endDx,nOrient*nAngle,nLength);
free_matrix((void**)endDy,nOrient*nAngle,nLength);
free_matrix((void**)startO,nOrient*nAngle,nLength);
free_matrix((void**)endO,nOrient*nAngle,nLength);
	free_matrix((void**)sinsh,nOrient,2*Lrange+1);
	free_matrix((void**)cossh,nOrient,2*Lrange+1);
}
}


/* store the constituent Gabor positon and orientaions of arcs centered at (0,0)
 for arcs centered at (x,y), just shift Gabor positions relatively*/

void activeCurve::arcShift() {
    int iOri, iAng, iPage;
    int dAngle, l;
    float theta, dTheta;
    int cAngleLimit = (nAngle-1)/2;
    startDx = int_matrix(nOrient*nAngle, nLength);
    startDy = int_matrix(nOrient*nAngle, nLength);
    
    endDx = int_matrix(nOrient*nAngle, nLength);
    endDy = int_matrix(nOrient*nAngle, nLength);
    
    startO = int_matrix(nOrient*nAngle, nLength);
    endO = int_matrix(nOrient*nAngle, nLength);
    
    for (iOri=0; iOri<nOrient; ++iOri){
        for (iAng = 0; iAng<nAngle;++iAng){
            dAngle = -cAngleLimit+iAng;
            iPage = iOri*nAngle+iAng;
            startDx[iPage][0] = 0;
            startDy[iPage][0] = 0;
            endDx[iPage][0]=0;
            endDy[iPage][0]=0;
            startO[iPage][0] = iOri;
            endO[iPage][0] = iOri;
            for (l=1; l<nLength; ++l){

                startO[iPage][l] = (iOri + l*dAngle)%nOrient;
                if (startO[iPage][l]<0) startO[iPage][l]+=nOrient;
                theta = PI/nOrient*(iOri + l*dAngle);
                dTheta = dAngle*PI/nOrient;
                startDx[iPage][l] = startDx[iPage][l-1] - floor((h*1.8)*cos(dTheta/2.0f)*sin(theta-dTheta/2.0f)+.5);
                startDy[iPage][l] = startDy[iPage][l-1] + floor((h*1.8)*cos(dTheta/2.0f)*cos(theta-dTheta/2.0f)+.5);
                
                endO[iPage][l] = (iOri - l*dAngle)%nOrient;
                if (endO[iPage][l]<0)  endO[iPage][l]+= nOrient;
                theta = PI/nOrient*(iOri + nOrient- l*dAngle);
                endDx[iPage][l] = endDx[iPage][l-1] - floor((h*1.8)*cos(dTheta/2.0f)*sin(theta+dTheta/2.0f)+.5);
                endDy[iPage][l] = endDy[iPage][l-1] + floor((h*1.8)*cos(dTheta/2.0f)*cos(theta+dTheta/2.0f)+.5);
            }
        }
    }
    
    
}
	


	
/*Store local deformation range of Gobor primitives, in order to save computation*/
void activeCurve::storeShift() {
    int o, l;
    double theta;
    
    sinsh = int_matrix(nOrient, Lrange+Lrange+1);
    cossh = int_matrix(nOrient, Lrange+Lrange+1);
    for (o=0; o<nOrient; o++) {
        theta = PI*o/nOrient;
        for (l=-Lrange; l<=Lrange; l++) {
            sinsh[o][l+Lrange] = ROUND(l*sin(theta));
            cossh[o][l+Lrange] = ROUND(l*cos(theta));
        }
    }
}


/* for Gabor(x, y, orientation = ind), find local maximum in image i */
float activeCurve::shiftmax(int i, int ind, int x, int y, int *rm) {
    float m;
    int x1, y1, l, ml, mx, my, de, d, d1, here, mo, md;
    mx = x; my=y;mo = ind;
     
    m = NEGMAX;
    for (l=-Lrange; l<=Lrange; l++) {
        x1 = x + cossh[ind][l+Lrange];
        y1 = y + sinsh[ind][l+Lrange];   /* shifting in normal direction */
        if ((x1>=1)&&(x1<=sx)&&(y1>=1)&&(y1<=sy)) {
            here = px(x1, y1, sx, sy);
            for (de=-Orange; de<=Orange; de++) {
                d = de+ind;
                d1 = d;
                if (d<0)
                    d1 = d+nOrient;
                if (d>=nOrient)
                    d1 = d-nOrient;   /* shifting in orientation */
                if (S1map[d1*1+i][here]>m) {
                    m = S1map[d1*1+i][here];   /* local maximization */
                    ml = l; mx = x1; my = y1; mo = d1; md = de;
                }
            }
        }
    }
    rm[0] = ml; rm[1] = mx; rm[2] = my; rm[3] = mo; rm[4] = md;
    return(m);
}




	
/* draw the symbol of Gabor(x0, y0, orientation = ind) with intensity w */
void activeCurve::draw(float *symo, int x0, int y0, int ind, float w) {
    int x, y;
    float a;
    
    for (x=x0-h; x<=x0+h; x++)
        for (y=y0-h; y<=y0+h; y++) {
        if ((x>=1)&&(x<=sx)&&(y>=1)&&(y<=sy)) {
            a = allsymbol[ind][px(x-x0+h+1, y-y0+h+1, 2*h+1, 2*h+1)];
			a = a * w;
            if (symo[px(x, y, sx, sy)]<a)         
		     symo[px(x, y, sx, sy)] = w;
        }
    }
}


/*find deformed positions of each Gabor Primive in an arc*/
void activeCurve::deformAndDraw() {
    int i, mi, cx, cy, mx, my, rm[5];
    float mm;
    int iLen, iCache;
    int len, ori, ang;    

	int nimage =1; 
    /*draw deformed template*/
    for (i=0; i<nimage; i++) {
        ori = floor(imaxi[0+i*6]+.5);
        ang = floor(imaxi[1+i*6]+.5);
        len = floor(imaxi[2+i*6]+.5);
        cx = floor(imaxi[3+i*6]+.5);
        cy = floor(imaxi[4+i*6]+.5);
        iCache = ori*nAngle+ang;
        
        mx = cx+startDx[iCache][0];
        my = cy+startDy[iCache][0];
        mi = startO[iCache][0];
        mm = shiftmax(i, mi, mx, my, rm);
       
        draw(sym, rm[1], rm[2], rm[3], mm/6.0f);
        for(iLen = 1;iLen<=len;++iLen){
			/*Gabor in one end*/
            iCache = ori*nAngle+ang;
            mx = cx+startDx[iCache][iLen];
            my = cy+startDy[iCache][iLen];
            mi = startO[iCache][iLen];
            mm = shiftmax(i, mi, mx, my, rm);
            draw(sym, rm[1], rm[2], rm[3], mm/6.0f);

            /*Gabor in another end*/
            mx = cx+endDx[iCache][iLen];
            my = cy+endDy[iCache][iLen];
            mi = endO[iCache][iLen];
            mm = shiftmax(i, mi, mx, my, rm);          
            draw(sym, rm[1], rm[2], rm[3], mm/6.0f);            
        }
    }
}



bool activeCurve::drawDeformedLine(line max_line, float *map){
	/*ori,angle,length,cx,cy*/
	imaxi[0]=max_line.orient;
	imaxi[1]=0;
	imaxi[2]=max_line.length;
	imaxi[3]=max_line.x;
	imaxi[4]=max_line.y;


	sym = map;

	deformAndDraw();
	return true;
}
